package com.liuyun.bouncycastle;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

/**
 * 引入第三方提供者，以便使用更多的加解密算法
 * 提供者：org.bouncycastle.jce.provider.BouncyCastleProvider
 * <p>
 * Copyright: (C), 2021/1/19 23:14
 * <p>
 * <p>
 * Company Information & Data Security Solutions Co., Ltd.
 *
 * @author LiuYun liujw@idss-cn.com
 * @version 1.0
 * @see org.bouncycastle.jce.provider.BouncyCastleProvider
 */
public class BouncyCastleUtil {
    static {
        // 引入加解密的提供者: MD4 SHA384等，弥补JDK的不足
        // 若注释掉以下代码，会报错，提示不支持指定的算法：NoSuchAlgorithmException
        Security.addProvider(new BouncyCastleProvider());
    }

    public static void main(String[] args) throws NoSuchAlgorithmException {
        // 加密 1亿次
        long count = 100L * 1000L * 1000L;
        byte[] data = "12345".getBytes(StandardCharsets.UTF_8);
        testMult("SHA-1", data, count);
        testMult("SHA-256", data, count);
        testMult("SHA-512", data, count);
    }

    private static void testMult(String algorithm, byte[] data, long count) throws NoSuchAlgorithmException {
        long startTime = System.nanoTime();
        for (int i = 0; i < count; i++) {
            encode(data, algorithm);
        }
        long nanoTime = System.nanoTime() - startTime;
        final int expectLength = 7;
        if (algorithm.length() < expectLength) {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < expectLength - algorithm.length(); i++) {
                builder.append(" ");
            }

            algorithm += builder.toString();
        }
        System.out.println(algorithm
                + " 加密" + count + "次，耗时：【"
                + " 纳秒=" + nanoTime
                + ", 微秒=" + nanoTime / (1000L)
                + ", 毫秒=" + nanoTime / (1000L * 1000L)
                + ", 秒=" + nanoTime / (1000L * 1000L * 1000L)
                + "】 平均每次耗时" + nanoTime / count + "纳秒");
    }

    /**
     * 计算摘要
     *
     * @param input
     * @param algorithm
     * @return 哈希值
     * @throws NoSuchAlgorithmException
     */
    public static String encodeToHexString(String input, String algorithm) throws NoSuchAlgorithmException {
        byte[] digest = encode(input.getBytes(StandardCharsets.UTF_8), algorithm);
        return toHex(digest);
    }

    /**
     * @param input
     * @param algorithm
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static byte[] encode(byte[] input, String algorithm) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance(algorithm);
        md.update(input);
        return md.digest();
    }

    private static String toHex(byte[] digest) {
        return new String(Hex.encode(digest), StandardCharsets.UTF_8);
    }
}
